DEV Community

Cover image for Telegram Web Apps (Reopening last page)
Bogdan Aksenov
Bogdan Aksenov

Posted on

Telegram Web Apps (Reopening last page)

On April 15, the telegram team gave us the opportunity to develop web bots.

Now, interaction with bots has become very interactive, as we have the ability to integrate full-fledged web applications into bots.

In the process of developing a web app bot, I ran into a problem that after closing the web app interface and reopening it, we lose the last link on which the user was, and the web application opens from the main page.

At first, this may not seem like a problem, but it's actually very easy to accidentally close the web window, since it doesn't open to full screen, and to close it, just drag it down, and we lose all the previous state of the application.

In my application I use React, mobX and React Router Dom v6. The first thing that comes to mind is to subscribe to navigation changes and store the last value in localStorage or cookies, I chose cookies, with a lifetime of 10 minutes.

Let's look at the code.

Create location-provider.tsx

import React from "react"
import { useLocation, useNavigate } from "react-router-dom"
import Cookies from "js-cookie"

interface LocationProviderProps {
  children: React.ReactNode
}

const LocationProvider: React.FC<LocationProviderProps> = ({ children }) => {
  const location = useLocation()
  const navigate = useNavigate()

  React.useEffect(() => {
    const currentLocation = Cookies.get("location_app")
    if (!currentLocation) return
    navigate(currentLocation)
  }, [])

  React.useEffect(() => {
    const tenMinutes = new Date(new Date().getTime() + 10 * 60 * 1000)
    Cookies.set("location_app", location.pathname, {
      expires: tenMinutes,
    })
  }, [location])

  return <>{children}</>
}

export default LocationProvider
Enter fullscreen mode Exit fullscreen mode

Import it into App.tsx and wrap our routes

import React from "react"
import { BrowserRouter, Route, Routes } from "react-router-dom"
import LocationProvider from "providers/location-provider"

import { AppsPage } from "./pages/apps"
import { DevelopersPage } from "./pages/developers"
import { FavoritesPage } from "./pages/favorites"
import { SearchPage } from "./pages/search"

function App() {
  return (
    <BrowserRouter>
      <LocationProvider>
        <Routes>
          <Route index element={<AppsPage />} />
          <Route path="/apps" element={<AppsPage />} />
          <Route path="/apps/:appId" element={<AppDetailPage />} />
          <Route path="/favorites" element={<FavoritesPage />} />
          <Route path="/search" element={<SearchPage />} />
          <Route path="/developers" element={<DevelopersPage />} />
        </Routes>
      </LocationProvider>
    </BrowserRouter>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

Great, now after closing and opening the web application, the last page will open, but!

There is a problem here, this is that if, when the application is open, go to another page through the URL input line, we will be redirected back.
But web bots do not have an address bar, so you can stop there?

Yes, if this is enough for you, then it will work in web bots. But you will have concerns opening your web application outside of web bots, for example you have an online store, you would like to interact with it in telegram web app and just as a web application available at the address, what then?

We think further, in the DOM API, the window object has an event onbeforeunload, it seems that this is what we need, we will save the last URL before closing the web application, we try.

Update our location-provider.tsx

import React from "react"
import { useLocation, useNavigate } from "react-router-dom"
import Cookies from "js-cookie"

interface LocationProviderProps {
  children: React.ReactNode
}

const LocationProvider: React.FC<LocationProviderProps> = ({ children }) => {
  const location = useLocation()
  const navigate = useNavigate()

  React.useEffect(() => {
    const currentLocation = Cookies.get("location_app")
    if (!currentLocation) return
    navigate(currentLocation)
  }, [])

  React.useEffect(() => {
    window.onbeforeunload = (e: BeforeUnloadEvent) => {
      e.preventDefault()
      const tenMinutes = new Date(new Date().getTime() + 10 * 60 * 1000)
      Cookies.set("location_app", location.pathname, {
        expires: tenMinutes,
      })
    }
  }, [location])

  return <>{children}</>
}

export default LocationProvider
Enter fullscreen mode Exit fullscreen mode

We try to walk around the application through the address bar, there is no redirect back, excellent, the link is also saved when closing the tab with the application, which is what we wanted!
We try in telegrams, bam, and here it doesn’t work at all, why?

The fact is that telegram opens a browser window in the so-called WebView, I'm not strong in developing mobile applications, but I know that this thing allows you to open a browser inside mobile applications, but they have their limitations and this is just one of them.

What then? An splendid solution would be to return to the first option, but enable caching only for telegram web app.
Let's take a look at what we got.

import React from "react"
import { useLocation, useNavigate } from "react-router-dom"
import Cookies from "js-cookie"

interface LocationProviderProps {
  children: React.ReactNode
}

const LocationProvider: React.FC<LocationProviderProps> = ({ children }) => {
  if (!window.Telegram.WebApp.initData.length) {
    return <>{children}</>
  } else {
    return <LocationProviderInner>{children}</LocationProviderInner>
  }
}

const LocationProviderInner: React.FC<LocationProviderProps> = ({
  children,
}) => {
  const location = useLocation()
  const navigate = useNavigate()

  const redirectToLastPage = () => {
    const currentLocation = Cookies.get("location_app")
    if (!currentLocation) return
    navigate(currentLocation)
  }

  React.useEffect(() => {
    if (location.key === "default") redirectToLastPage()

    Cookies.set("location_app", location.pathname, {
      expires: new Date(new Date().getTime() + 10 * 60 * 1000), // 10 min
    })
  }, [location.key])

  return <>{children}</>
}

export default LocationProvider
Enter fullscreen mode Exit fullscreen mode

Now, caching will work for us only if the application is launched from the web bot's telegram.

Thanks for reading!

Discussion (0)